/*
 * Dictionary class, see the documentation for the Windows Script Host object
 * Script.Dictionary.
 *
 * NOTE: I wrote this prior to discovering that associative arrays in JScript 
 * This can is still handy though since some methods, like remove, are far 
 * quicker than the trying to do the same with an associative array since 
 * JScript doesn't have the equivalent of Python's del.
 *
 * Example:
 * var dictionary = new Dictionary({1: 'this is'}, {100: 'a test'});
 * print(dictionary.item(1));
 * print(dictionary.item(100));
 * 
 * Displays;
 * this is
 * a test
 */
// Get the keys of the dictionary as an array.
function Dictionary_keys() {
  return (new VBArray(this.dictionary.Keys())).toArray();
}

// Get the items of the dictionary as an array.
function Dictionary_items() {
  return (new VBArray(this.dictionary.Items()).toArray());
}

// Get an array of key, value pairs from a dictionary.
function Dictionary_keyItems() {
  var associative_array = {};
  var keys = this.keys();
  for (var i in keys) {
    var key = keys[i];
    associative_array[key] = this.item(key);
  }
  return associative_array;
}

// Wrapper around Script.Dictionary.Exists.
function Dictionary_exists(key) {
  return this.dictionary.Exists(key);
}

// Get an item by key, if the key doesn't exist in the dictionary 
// undefined is returned.
function Dictionary_get(key) {
  return this.exists(key) ? this.item(key) : undefined;
}

// Wrapper around Script.Dictionary.Item property.
// To assign a key a vlaue use the add() function.
function Dictionary_item(key) {
  return this.dictionary.Item(key);
}

// Wrapper around Script.Dictionary.Key property
// To assign a key a vlaue use the add() function.
function Dictionary_key(key) {
  return this.dictionary.Key(key);
}

// Add / replace a key value pair.
function Dictionary_add(key, item) {
  // Associative arrays store keys as strings so we have to convert it back
  // to an int so lookups work correctly.
  var key_string = key.toString();
  if (key_string.match(/^-?\d+/)) {
    key = parseInt(key_string);
  }
  if (this.exists(key)) {
    this.remove(key);
  }
  this.dictionary.Add(key, item);
  this.length += 1;
}

// Wrapper around Script.Dictionary.Remove method.
function Dictionary_remove(key) {
  this.dictionary.Remove(key);
  this.length -= 1;
}

// Wrapper around Script.Dictionary.RemoveAll
function Dictionary_removeAll() {
  this.length = 0;
  this.dictionary.RemoveAll();
}

// Creates a dictionary object from the specified array of key value pairs.
function Dictionary_addArray(sequence) {
  if (sequence instanceof Array) {
    for (var i in sequence) {
      var key_value_pair = sequence[i];
      if (!((key_value_pair instanceof Array) &&
          key_value_pair.length == 2)) {
        throw 'Sequence doesn\'t contain key value pairs'
      }
      this.add(key_value_pair[0], key_value_pair[1]);
    }
  } else if (sequence instanceof Object) {
    for (var i in sequence) {
      // Associative arrays store keys as strings.
      this.add(i, sequence[i]);
    } 
  } else {
    throw 'Specified sequence object isn\'t an array or associative array'
  }
}

// Display the dictionary like Python.
function Dictionary_toString() {
  var associative_array = this.keyItems();
  var string = '{ ';
  for (var i in associative_array) {
    string += i.toString() + ': ' + associative_array[i].toString() +
      ', ';
  }
  string += '} ';
  return string;
}

// Constructor.
function Dictionary(associative_array) {
  // The underlying dictionary object.
  this.dictionary = new ActiveXObject('Scripting.Dictionary');
  this.length = 0;

  // If an array of key value pairs was specified initialize the dictionary.
  if (!isUndefined(associative_array)) {
    this.addArray(associative_array);
  }
}

// Fix up the class methods.
Dictionary.prototype.add = Dictionary_add;
Dictionary.prototype.keys = Dictionary_keys;
Dictionary.prototype.items = Dictionary_items;
Dictionary.prototype.keyItems = Dictionary_keyItems;
Dictionary.prototype.exists = Dictionary_exists;
Dictionary.prototype.get = Dictionary_get;
Dictionary.prototype.item = Dictionary_item;
Dictionary.prototype.key = Dictionary_key;
Dictionary.prototype.remove = Dictionary_remove;
Dictionary.prototype.removeAll = Dictionary_removeAll;
Dictionary.prototype.addArray = Dictionary_addArray;
Dictionary.prototype.toString = Dictionary_toString;
